﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace RichLabelSpace
{
    class SimpleStack
    {
        int cur_index;
        int cur_width;
        List<List<RichLabelComponent>> line_list;
        public RichLabelComponent[] CurList { get { return line_list[cur_index].ToArray(); } }
        public int CurLine { get { return cur_index; } }
        public int CurWidth { get { return cur_width; } }
        public List<List<RichLabelComponent>> LineList { get { return line_list; } }

        public void PushInCurLine(RichLabelComponent comp)
        {
            line_list[cur_index].Add(comp);
            cur_width += comp.m_ui_widget.width;
        }

        public void MoveToNextLine()
        {
            if(cur_index == -1 || line_list[cur_index].Count > 0 || line_list[cur_index] == null)
            {
                ++cur_index;
                cur_width = 0;
                line_list.Insert(cur_index,new List<RichLabelComponent>());
            }
        }

        public SimpleStack()
        {
            line_list = new List<List<RichLabelComponent>>();
            cur_index = -1;
            cur_width = 0;
            MoveToNextLine();
        }
    }

    internal class RichCompSortHelper
    {
        // 重新设置行数排列
        public static List<List<RichLabelComponent>> ResetLines(Vector2 size, List<RichLabelComponent> list)
        {
            SimpleStack line_stack = new SimpleStack();
            // 分行
            int count = 0;
            int cur_index = 0;
            var size_x = (int)size.x;
            do
            {
                count = list.Count;
                for (int i = cur_index; i < count; ++i, ++cur_index)
                {
                    var comp = list[i];
                    var width = comp.m_ui_widget.width;

                    // 换行处理
                    if (comp.m_component_type == RichComponentType.Label)
                    {
                        if (ResetLabelComp2(list,line_stack,ref cur_index, comp)) break;
                    }

                    if (width > size_x || line_stack.CurWidth + width > size_x)
                    {
                        // 已经满一行了。直接换行处理，不要再进行计算
                        if(line_stack.CurWidth >= size_x)
                        {
                            line_stack.MoveToNextLine();
                            break;
                        }

                        bool need_move_next_line = true;
                        if (comp.m_component_type == RichComponentType.Label)
                        {
                            if (ResetLabelComp1(list, line_stack, cur_index, size_x, comp)) need_move_next_line = false;
                        }
                        else // 假设是其它类型，且其长度又长于一行的最长长度，这里需要强制加塞进一行中。这里面的代码会被执行。
                        {
                            ++cur_index;
                            line_stack.MoveToNextLine();
                            line_stack.PushInCurLine(comp);
                            need_move_next_line = false;
                        }

                        /*ps 如果以上都没有处理掉，就只有一种情况，那就是不能拆分文字，只能在下面一行显示*/
                        if (need_move_next_line)  line_stack.MoveToNextLine();
                        break;
                    }
                    else
                    {
                        line_stack.PushInCurLine(comp);
                    }
                }
            } while (cur_index < count);

            return line_stack.LineList;
        }

        /// <summary>
        /// 对文字进行切割
        /// </summary>
        /// <returns>返回false表示当前行装不下字体了</returns>
        private static bool ResetLabelComp1(List<RichLabelComponent> list, SimpleStack line_stack, int cur_index, int size_x, RichLabelComponent comp)
        {
            // 如果是文本，就进行切割,并且退出此次循环 。否则直接换行
            List<string> line_list = new List<string>();
            var lab_comp = (RichLabel)comp;
            var text = lab_comp.Text;

            // 检查切割后的label能否在这行显示部分字符串
            var ui_label = (UILabel)lab_comp.m_ui_widget;
            var residue_width = Mathf.FloorToInt(size_x) - line_stack.CurWidth;
            string[] lines = CalculateSubstringLength(residue_width, line_stack.CurWidth, text, ui_label);
            if (lines != null && lines.Length > 1)
            {
                line_list.AddRange(lines);
            }


            var _lines = line_list.ToArray();
            if (_lines != null && _lines.Length > 1)
            {
                var array = lab_comp.SubComponent(_lines);
                if (array != null)
                {
                    list.InsertRange(cur_index + 1, array);
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 检出换行符
        /// </summary>
        /// <returns>返回false有换行</returns>
        private static bool ResetLabelComp2(List<RichLabelComponent> list, SimpleStack line_stack,ref int cur_index, RichLabelComponent comp)
        {
            var lab = (RichLabel)comp;
            var text = lab.Text;
            if (text == "\n")
            {
                line_stack.PushInCurLine(comp);
                line_stack.MoveToNextLine();
                ++cur_index;
                return true;
            }
            else
            {
                if (text.Contains('\n'))    // 检查是否有分行符号
                {
                    List<string> lines = new List<string>();
                    while (text.Length > 0)
                    {
                        var index = text.IndexOf("\n");
                        if (index > 0)
                        {
                            var _start = text.Substring(0, index);
                            var _spece = text.Substring(index, 1);
                            text = text.Remove(0, index + 1);
                            lines.Add(_start);
                            lines.Add(_spece);
                        }
                        else if (index == 0)
                        {
                            var _spece = text.Substring(0, 1);
                            text = text.Remove(0, index + 1);
                            lines.Add(_spece);
                        }
                        else
                        {
                            lines.Add(text);
                            text = "";
                        }
                    }

                    List<string> line_list = new List<string>();
                    line_list.AddRange(lines);
                    var _lines = line_list.ToArray();
                    if (_lines != null && _lines.Length > 1)
                    {
                        var array = lab.SubComponent(_lines);
                        if (array != null)
                        {
                            list.InsertRange(cur_index + 1, array);
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        private static string[] CalculateSubstringLength(int residue_width, int cur_width, string text, UILabel ui_label)
        {   
            // 二分法查找
            var can_continue = true;
            var l_val = 0;
            var r_val = text.Length;
            var thum = r_val; 
            while(l_val < r_val && can_continue)
            {
                var cur_length = l_val + thum;
                var sub_val = text.Substring(0,cur_length);
                var vec2 = CalculatePrintedSize(ui_label, sub_val);
                
                //刚刚好
                if(vec2.x == residue_width)
                {
                    can_continue = false;
                    break;
                }
                else if (vec2.x > residue_width) r_val = cur_length; // 超出了
                else l_val = cur_length;   //小了
                
                thum = (r_val - l_val) / 2;

                // 最后两个数的判定方法
                if(thum == 0 || l_val + 1 == r_val)
                {
                    can_continue = false;
                    sub_val = text.Substring(0,r_val);
                    l_val = CalculatePrintedSize(ui_label, sub_val).x <= residue_width ? r_val : l_val;
                    thum = 0;
                }
            }

            var sub_count = l_val + thum;
            if (sub_count > 0)
            {
                string[] temp_lines = new string[2];
                temp_lines[0] = text.Substring(0, sub_count);
                temp_lines[1] = text.Remove(0, sub_count);
                return temp_lines;
            }

            return null;
        }

        // 重新设置位置
        public static void ResetPosition(Transform transform, Vector2 size, List<List<RichLabelComponent>> lines, NGUIText.Alignment alignment,int line_spacing)
        {
            //根据排版计算位置
            var cur_max_height = 0;
            for(int m = 0; m < lines.Count; ++m)
            {
                var line = lines[m];
                var max_size = CalulateMaxSize(line);
                var cur_line_height = (int)max_size.y;
                if (cur_line_height > 0)
                {
                    // 向下增长
                    var pos_y = cur_max_height - cur_line_height / 2;
                    cur_max_height -= cur_line_height;
                    var cur_line_width = 0;
                    //计算起始点
                    switch (alignment)
                    {
                        case NGUIText.Alignment.Left:
                            cur_line_width = 0;
                            break;
                        case NGUIText.Alignment.Right:
                            cur_line_width = Mathf.FloorToInt(size.x - max_size.x);
                            break;
                        //case NGUIText.Alignment.Automatic:
                        //case NGUIText.Alignment.Justified:
                        //case NGUIText.Alignment.Center:
                        default:
                            cur_line_width = Mathf.FloorToInt((size.x - max_size.x) / 2);
                            break;
                    }
                    for (var n = 0; n < line.Count; ++n)
                    {
                        var comp = line[n];
                        var cur_comp_width = comp.m_ui_widget.width;
                        var pox_x = cur_line_width;
                        comp.SetPosition(new Vector3(pox_x, pos_y, 0));
                        cur_line_width += cur_comp_width;
                    }
                }
            }
        }

        private static Vector2 CalulateMaxSize(List<RichLabelComponent> line)
        {
            var max_height = 0;
            var max_width = 0;
            if (line != null && line.Count > 0)
            {
                foreach (var comp in line)
                {
                    max_height = comp.m_ui_widget.height > max_height ? comp.m_ui_widget.height : max_height;
                    max_width = comp.m_ui_widget.width > max_width ? comp.m_ui_widget.width : max_width;
                }
            }

            return new Vector2(max_width, max_height);
        }
        public static void ResetDepth(List<RichLabelComponent> list) 
        {
            Dictionary<RichComponentType, int> depth_dict = new Dictionary<RichComponentType, int>();
            foreach (var ui in list)
            {
                if (ui.m_ui_widget.gameObject.activeSelf) 
                {
                    if(depth_dict.ContainsKey(ui.m_component_type))
                    {
                        ui.m_ui_widget.depth = depth_dict[ui.m_component_type];
                    }
                    else
                    {
                        depth_dict.Add(ui.m_component_type, ui.m_ui_widget.depth);
                    }
                }
            }
        }

        ////计算单个文字的准确位置
        ////参数1是显示字符串的UI控件，参数2是要显示的所有文字，参数3是要计算位置的文字的index
        //private static Vector2 CalculateSinglePosition(UILabel label, string text, int index)
        //{
        //    BetterList<Vector3> verts = new BetterList<Vector3>();
        //    BetterList<int> indices = new BetterList<int>();
        //    UpdateCharacterPosition(label, text, out verts, out indices);
        //    index = indices.IndexOf(index);
        //    Vector3 p1;
        //    if (index != -1 && verts.size > index * 2 + 1)
        //    {
        //        p1 = (verts[index * 2] + verts[index * 2 + 1]) * 0.5f;
        //    }
        //    else
        //    {
        //        p1 = (verts[verts.size - 1] + verts[verts.size - 2]) * 0.5f;
        //    }

        //    return p1;
        //}

        //计算显示文字的实际显示范围
        //这个方法可以计算出整个文本的大小，NGUIText.CalculatePrintedSize的计算结果会有问题
        private static Vector2 CalculatePrintedSize(UILabel label, string text)
        {
            // float minX = 0, maxX = 0, minY = 0, maxY = 0;

            // BetterList<Vector3> verts = new BetterList<Vector3>();
            // //BetterList<int> indices = new BetterList<int>();

            // UpdateCharacterPosition(label, text, out verts/*, indices*/);

            // foreach (Vector3 cor in verts)
            // {
            //     if (cor.x < minX)
            //         minX = cor.x;
            //     if (cor.x > maxX)
            //         maxX = cor.x;
            //     if (cor.y < minY)
            //         minY = cor.y;
            //     if (cor.y > maxY)
            //         maxY = cor.y;
            // }
            // return new Vector2(maxX - minX, maxY - minY);
            // // return NGUIText.CalculatePrintedSize(text);
            //var old_text = label.text;
            //label.text = text;
            //var size = label.localSize;
            //label.text = old_text;

            label.UpdateNGUIText();
            var size = NGUIText.CalculatePrintedSize(text);
            //Debug.Log(text + "   size : " + size.ToString());
            return size;
        }

        private static void UpdateCharacterPosition(UILabel label, string str, out BetterList<Vector3> verts/*, BetterList<int> indices*/)
        {
            //计算当前所有字符的位置  
            label.text = str;
            label.UpdateNGUIText();
            BetterList<Vector3> tempVerts = new BetterList<Vector3>();
            BetterList<int> tempIndices = new BetterList<int>();

            NGUIText.PrintExactCharacterPositions(str, tempVerts, tempIndices);
            verts = tempVerts;
            //indices.AddRange(tempIndices);

            for (int i = 0; i < verts.size; i++)
            {
                switch (label.pivot)
                {
                    case UIWidget.Pivot.TopLeft:
                        {
                            verts[i] += new Vector3(0, 0, 0);
                            break;
                        }
                    case UIWidget.Pivot.Top:
                        {
                            verts[i] += new Vector3(-label.width * 0.5f, 0, 0);
                            break;
                        }
                    case UIWidget.Pivot.TopRight:
                        {
                            verts[i] += new Vector3(-label.width, 0, 0);
                            break;
                        }
                    case UIWidget.Pivot.Left:
                        {
                            verts[i] += new Vector3(0, label.height * 0.5f, 0);
                            break;
                        }
                    case UIWidget.Pivot.Center:
                        {
                            verts[i] += new Vector3(-label.width * 0.5f, label.height * 0.5f, 0);
                            break;
                        }
                    case UIWidget.Pivot.Right:
                        {
                            verts[i] += new Vector3(-label.width, label.height * 0.5f, 0);
                            break;
                        }
                    case UIWidget.Pivot.BottomLeft:
                        {
                            verts[i] += new Vector3(0, label.height, 0);
                            break;
                        }
                    case UIWidget.Pivot.Bottom:
                        {
                            verts[i] += new Vector3(-label.width * 0.5f, label.height, 0);
                            break;
                        }
                    case UIWidget.Pivot.BottomRight:
                        {
                            verts[i] += new Vector3(-label.width, label.height, 0);
                            break;
                        }
                }
            }
        }
    }
}
